#include<vector>
#include<ctime>
#include<cmath>
#include<string>
#include<fstream>
#include"Util.h"
#include"StringPool.h"
#include"variable.h"
#include"DependencyInstance.h"
#include"KBestParseForest.h"
#include"DependencyPipe3OGSibling.h"
using namespace std;

DependencyPipe3OGSibling::DependencyPipe3OGSibling(ParserOptions *options) : DependencyPipe2O(options){}

DependencyPipe3OGSibling::~DependencyPipe3OGSibling(){}

bool DependencyPipe3OGSibling::isCoord(DependencyInstance *instance, int par, int ch1){
	if(ch1 == par){
		return false;
	}

	vector<string*> *pos = instance->postags;
	vector<string*> *forms = instance->forms;

	string par_pos = *(*pos)[par];
	string ch1_pos = *(*pos)[ch1];
	string nch1_pos = *(*pos)[ch1 + 1];

	string ch1_form = *(*forms)[ch1];

	//coordination features
	bool coord = ((coordSet.count(ch1_pos) > 0) || ((commaSet.count(ch1_form) > 0) && (coordSet.count(nch1_pos) > 0)));
	return coord;
}

void DependencyPipe3OGSibling::addExtendedFeatures(DependencyInstance *instance, FeatureVector *fv){
	const int instanceLength = instance->length();
	vector<int> *heads = instance->heads;

	for(int i = 0; i < instanceLength; i++){
		if((*heads)[i] == -1 && i != 0){
			continue;
		}

		// right children
		int prev = i;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		// left children
		prev = i;
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i) {
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		//left features;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				for(int k = i + 1; k < instanceLength; k++){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}

		//right features
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i){
				for(int k = i - 1; k >= 0; k--){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}

		//left grand trip features;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				prev = j;
				for(int k = j + 1; k < instanceLength; k++){
					if((*heads)[k] == j){
						addGrandTripFeatures(instance, i, j, prev, k, fv);
						addGrandSibFeatures(instance, i, prev, k, prev == j, fv);
						if(isCoord(instance, j, prev)){
							addCoordFeatures(instance, i, j, k, fv);
						}
						prev = k;
					}
				}

				prev = j;
				for(int k = j - 1; k > i; k--){
					if((*heads)[k] == j){
						addGrandTripFeatures(instance, i, j, prev, k, fv);
						addGrandSibFeatures(instance, i, prev, k, prev == j, fv);
						if(isCoord(instance, j, prev)){
							addCoordFeatures(instance, i, j, k, fv);
						}
						prev = k;
					}
				}
			}
		}

		//right grand trip features;
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i){
				prev = j;
				for(int k = j + 1; k < i; k++){
					if((*heads)[k] == j){
						addGrandTripFeatures(instance, i, j, prev, k, fv);
						addGrandSibFeatures(instance, i, prev, k, prev == j, fv);
						if(isCoord(instance, j, prev)){
							addCoordFeatures(instance, i, j, k, fv);
						}
						prev = k;
					}
				}

				prev = j;
				for(int k = j - 1; k >= 0; k--){
					if((*heads)[k] == j){
						addGrandTripFeatures(instance, i, j, prev, k, fv);
						addGrandSibFeatures(instance, i, prev, k, prev == j, fv);
						if(isCoord(instance, j, prev)){
							addCoordFeatures(instance, i, j, k, fv);
						}
						prev = k;
					}
				}
			}
		}
	}
}

void DependencyPipe3OGSibling::addGrandSibFeatures(DependencyInstance *instance, int gpar, int ch1, int ch2, bool isST, FeatureVector *fv){
	vector<string*> *pos = instance->postags;
	vector<string*> *cpos = instance->cpostags;
	vector<string*> *forms = instance->forms;

	bool flag;
	// ch1 is always the closest to par
	string gpar_pos = *(*pos)[gpar];
	string ch1_pos = isST ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = *(*pos)[ch2];

	string gpar_cpos = *(*cpos)[gpar];
	string ch1_cpos = isST ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = *(*cpos)[ch2];

	string gpar_form = *(*forms)[gpar];
	string ch1_form = isST ? "STWRD" : *(*forms)[ch1];
	string ch2_form = *(*forms)[ch2];

	//GSibling
	//POS
	string GSibs_pos = gpar_pos + "_" + ch1_pos + "_" + ch2_pos;
	string tmp = "POS_GSIBS=" + GSibs_pos;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//CPOS
	string GSibs_cpos = gpar_cpos + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "CPOS_GSIBS=" + GSibs_cpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//FORM-POS
	string GSibs_fpos = gpar_form + "_" + ch1_pos + "_" + ch2_pos;
	tmp = "FPOSG_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fpos = gpar_pos + "_" + ch1_form + "_" + ch2_pos;
	tmp = "FPOSC1_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fpos = gpar_pos + "_" + ch1_pos + "_" + ch2_form;
	tmp = "FPOSC2_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fpos = gpar_form + "_" + ch1_form + "_" + ch2_pos;
	tmp = "FPOSGC1_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fpos = gpar_pos + "_" + ch1_form + "_" + ch2_form;
	tmp = "FPOSC12_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fpos = gpar_form + "_" + ch1_pos + "_" + ch2_form;
	tmp = "FPOSGC2_GSIBS=" + GSibs_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//FORM-CPOS
	string GSibs_fcpos = gpar_form + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "FCPOSG_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fcpos = gpar_cpos + "_" + ch1_form + "_" + ch2_cpos;
	tmp = "FCPOSC1_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fcpos = gpar_cpos + "_" + ch1_cpos + "_" + ch2_form;
	tmp = "FCPOSC2_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fcpos = gpar_form + "_" + ch1_form + "_" + ch2_cpos;
	tmp = "FCPOSGC1_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fcpos = gpar_cpos + "_" + ch1_form + "_" + ch2_form;
	tmp = "FCPOSC12_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GSibs_fcpos = gpar_form + "_" + ch1_cpos + "_" + ch2_form;
	tmp = "FCPOSGC2_GSIBS=" + GSibs_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//context features
	string gnt, c1nt, c2nt, gnc, c1nc, c2nc;
	string gpt, c1pt, c2pt, gpc, c1pc, c2pc;
	if(gpar < ch2){
		if(ch1 < ch2){
			gnt  = (gpar < ch1 - 1)               ? *(*pos)[gpar + 1] : "MPOS";
			c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < instance->length() - 1) ? *(*pos)[ch2 + 1]  : "EPOS";

			gpt  = (gpar > 0)                     ? *(*pos)[gpar - 1] : "SPOS";
			c1pt = (ch1 > gpar + 1)               ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < ch1 - 1)               ? *(*cpos)[gpar + 1] : "MCPOS";
			c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < instance->length() - 1) ? *(*cpos)[ch2 + 1]  : "ECPOS";

			gpc  = (gpar > 0)                     ? *(*cpos)[gpar - 1] : "SCPOS";
			c1pc = (ch1 > gpar + 1)               ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
		else{
			gnt  = (gpar < ch2 - 1)               ? *(*pos)[gpar + 1] : "MPOS";
			c1nt = (ch1 < instance->length() - 1) ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > 0)                     ? *(*pos)[gpar - 1] : "SPOS";
			c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > gpar + 1)               ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < ch2 - 1)               ? *(*cpos)[gpar + 1] : "MCPOS";
			c1nc = (ch1 < instance->length() - 1) ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > 0)                     ? *(*cpos)[gpar - 1] : "SCPOS";
			c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > gpar + 1)               ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
	}
	else{
		if(ch1 < ch2){
			gnt  = (gpar < instance->length() - 1)? *(*pos)[gpar + 1] : "EPOS";
			c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < gpar - 1)               ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > ch2 + 1)               ? *(*pos)[gpar - 1] : "MPOS";
			c1pt = (ch1 > 0)                      ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < instance->length() - 1)? *(*cpos)[gpar + 1] : "ECPOS";
			c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < gpar - 1)               ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > ch2 + 1)               ? *(*cpos)[gpar - 1] : "MCPOS";
			c1pc = (ch1 > 0)                      ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
		else{
			gnt  = (gpar < instance->length() - 1)? *(*pos)[gpar + 1] : "EPOS";
			c1nt = (ch1 < gpar - 1)               ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > ch1 + 1)               ? *(*pos)[gpar - 1] : "MPOS";
			c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > 0)                      ? *(*pos)[ch2 - 1]  : "SPOS";

			gnc  = (gpar < instance->length() - 1)? *(*cpos)[gpar + 1] : "ECPOS";
			c1nc = (ch1 < gpar - 1)               ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > ch1 + 1)               ? *(*cpos)[gpar - 1] : "MCPOS";
			c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > 0)                      ? *(*cpos)[ch2 - 1]  : "SCPOS";
		}
	}
	/* trigram context features */
	//POS
	string context = gpar_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gnt + "_" + c1nt + "_" + c2nt;
	tmp = "3GNPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gpt + "_" + c1pt + "_" + c2pt;
	tmp = "3GPPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	//CPOS
	context = gpar_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gnc + "_" + c1nc + "_" + c2nc;
	tmp = "3GNCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gpc + "_" + c1pc + "_" + c2pc;
	tmp = "3GPCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	/* bigram context features */
	//POS
	context = gpar_pos + "_" + ch1_pos + "_" + gnt + "_" + c1nt;
	tmp = "2GNPOS1_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_pos + "_" + ch1_pos + "_" + gpt + "_" + c1pt;
	tmp = "2GPPOS1_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = gpar_pos + "_" + ch2_pos + "_" + gnt + "_" + c2nt;
	tmp = "2GNPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_pos + "_" + ch2_pos + "_" + gpt + "_" + c2pt;
	tmp = "2GPPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_pos + "_" + ch2_pos + "_" + c1nt + "_" + c2nt;
	tmp = "2GNPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_pos + "_" + ch2_pos + "_" + c1pt + "_" + c2pt;
	tmp = "2GPPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	//CPOS
	context = gpar_cpos + "_" + ch1_cpos + "_" + gnc + "_" + c1nc;
	tmp = "2GNCPOS1_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_cpos + "_" + ch1_cpos + "_" + gpc + "_" + c1pc;
	tmp = "2GPCPOS1_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = gpar_cpos + "_" + ch2_cpos + "_" + gnc + "_" + c2nc;
	tmp = "2GNCPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_cpos + "_" + ch2_cpos + "_" + gpc + "_" + c2pc;
	tmp = "2GPCPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_cpos + "_" + ch2_cpos + "_" + c1nc + "_" + c2nc;
	tmp = "2GNCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch2_cpos + "_" + c1pc + "_" + c2pc;
	tmp = "2GPCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe3OGSibling::addCoordFeatures(DependencyInstance *instance, int gpar, int par, int ch2, FeatureVector *fv){
	vector<string*> *pos = instance->postags;
	vector<string*> *cpos = instance->cpostags;
	vector<string*> *forms = instance->forms;

	bool flag;
	// ch1 is always the closest to par
	string gpar_pos = *(*pos)[gpar];
	string par_pos = *(*pos)[par];
	string ch2_pos = *(*pos)[ch2];

	string gpar_cpos = *(*cpos)[gpar];
	string par_cpos = *(*cpos)[par];
	string ch2_cpos = *(*cpos)[ch2];

	string gpar_form = *(*forms)[gpar];
	string par_form = *(*forms)[par];
	string ch2_form = *(*forms)[ch2];

	//FORMS
	string coordination = gpar_form + "_" + par_form + "_" + ch2_form;
	string tmp = "3F_SCC=" + coordination;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_form;
	tmp = "2F1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	
	coordination = par_form + "_" + ch2_form;
	tmp = "2F2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	
	if(par_form == ch2_form){
		tmp = "SAMEW_SCC=" + string("WNULL");
		feat = pool->get(tmp);
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMEW_SCC=" + par_form;
		}
		else{
			tmp = "SAMEW_SCC=" + par_form;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMEWG_SCC=" + gpar_form + "_" + par_form;
		}
		else{
			tmp = "SAMEWG_SCC=" + gpar_form + "_" + par_form;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			pool->push_back(feat);
		}
	}

	/* 3gram coordination features */
	//POS
	coordination = gpar_pos + "_" + par_pos + "_" + ch2_pos;
	tmp = "3POS_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_pos + "_" + ch2_pos;
	tmp = "3FPOSG_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + par_form + "_" + ch2_pos;
	tmp = "3FPOSP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + par_pos + "_" + ch2_form;
	tmp = "3FPOSC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_form + "_" + ch2_pos;
	tmp = "3FPOSGP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + par_form + "_" + ch2_form;
	tmp = "3FPOSPC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_pos + "_" + ch2_form;
	tmp = "3FPOSGC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//CPOS
	coordination = gpar_cpos + "_" + par_cpos + "_" + ch2_cpos;
	tmp = "3CPOS_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_cpos + "_" + ch2_cpos;
	tmp = "3FCPOSG_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + par_form + "_" + ch2_cpos;
	tmp = "3FCPOSP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + par_cpos + "_" + ch2_form;
	tmp = "3FCPOSC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_form + "_" + ch2_cpos;
	tmp = "3FCPOSGP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + par_form + "_" + ch2_form;
	tmp = "3FCPOSPC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_cpos + "_" + ch2_form;
	tmp = "3FCPOSGC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* 2gram coordination features */
	//POS
	coordination = gpar_pos + "_" + par_pos;
	tmp = "2POSGP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_pos;
	tmp = "2FPOSGP1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + par_form;
	tmp = "2FPOSGP2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + ch2_pos;
	tmp = "2POSGC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + ch2_pos;
	tmp = "2FPOSGC1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_pos + "_" + ch2_form;
	tmp = "2FPOSGC2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_pos + "_" + ch2_pos;
	tmp = "2POSPC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_form + "_" + ch2_pos;
	tmp = "2FPOSPC1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_pos + "_" + ch2_form;
	tmp = "2FPOSPC2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//CPOS
	coordination = gpar_cpos + "_" + par_cpos;
	tmp = "2CPOSGP_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + par_cpos;
	tmp = "2FCPOSGP1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + par_form;
	tmp = "2FCPOSGP2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + ch2_cpos;
	tmp = "2CPOSGC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_form + "_" + ch2_cpos;
	tmp = "2FCPOSGC1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = gpar_cpos + "_" + ch2_form;
	tmp = "2FCPOSGC2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_cpos + "_" + ch2_cpos;
	tmp = "2CPOSPC_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_form + "_" + ch2_cpos;
	tmp = "2FCPOSPC1_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	coordination = par_cpos + "_" + ch2_form;
	tmp = "2FCPOSPC2_SCC=" + coordination;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* same coordination features */
	//POS
	if(par_pos == ch2_pos){
		tmp = "SAMET_SCC=" + string("TNULL");
		feat = pool->get(tmp);
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMET_SCC=" + par_pos;
		}
		else{
			tmp = "SAMET_SCC=" + par_pos;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMETG_SCC=" + gpar_pos + "_" + par_pos;
		}
		else{
			tmp = "SAMETG_SCC=" + gpar_pos + "_" + par_pos;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			pool->push_back(feat);
		}
		if(par_form == ch2_form){
			tmp = "SAMEB_SCC=" + string("TNULL") + "_"  + "WNULL";
			feat = pool->get(tmp);
			flag = add(feat, fv);
			if(flag){
				*feat = "SAMEB_SCC=" + par_pos + "_" + par_form;
			}
			else{
				tmp = "SAMEB_SCC=" + par_pos + "_" + par_form;
				feat = pool->get(tmp);
			}
			flag = add(feat, fv);
			if(flag){
				*feat = "SAMEBG_SCC=" + gpar_pos + "_" + par_pos + "_" + gpar_form + "_" + par_form;
			}
			else{
				tmp = "SAMEBG_SCC=" + gpar_pos + "_" + par_pos + "_" + gpar_form + "_" + par_form;
				feat = pool->get(tmp);
			}
			flag = add(feat, fv);
			if(flag){
				pool->push_back(feat);
			}
		}
	}

	//CPOS
	if(par_cpos == ch2_cpos){
		tmp = "SAMEC_SCC=" + string("CNULL");
		feat = pool->get(tmp);
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMEC_SCC=" + par_cpos;
		}
		else{
			tmp = "SAMEC_SCC=" + par_cpos;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			*feat = "SAMECG_SCC=" + gpar_cpos + "_" + par_cpos;
		}
		else{
			tmp = "SAMECG_SCC=" + gpar_cpos + "_" + par_cpos;
			feat = pool->get(tmp);
		}
		flag = add(feat, fv);
		if(flag){
			pool->push_back(feat);
		}
		if(par_form == ch2_form){
			tmp = "SAMER_SCC=" + string("CNULL") + "_"  + "WNULL";
			feat = pool->get(tmp);
			flag = add(feat, fv);
			if(flag){
				*feat = "SAMER_SCC=" + par_cpos + "_" + par_form;
			}
			else{
				tmp = "SAMER_SCC=" + par_cpos + "_" + par_form;
				feat = pool->get(tmp);
			}
			flag = add(feat, fv);
			if(flag){
				*feat = "SAMERG_SCC=" + gpar_cpos + "_" + par_cpos + "_" + gpar_form + "_" + par_form;
			}
			else{
				tmp = "SAMERG_SCC=" + gpar_cpos + "_" + par_cpos + "_" + gpar_form + "_" + par_form;
				feat = pool->get(tmp);
			}
			flag = add(feat, fv);
			if(flag){
				pool->push_back(feat);
			}
		}
	}
}

void DependencyPipe3OGSibling::addGrandTripFeatures(DependencyInstance *instance, int gpar, int par, int ch1, int ch2, FeatureVector *fv){
	vector<string*> *pos = instance->postags;
	vector<string*> *cpos = instance->cpostags;
	vector<string*> *forms = instance->forms;

	bool flag;
	// ch1 is always the closest to par
	string gpar_pos = *(*pos)[gpar];
	string par_pos = *(*pos)[par];
	string ch1_pos = ch1 == par ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = *(*pos)[ch2];

	string gpar_cpos = *(*cpos)[gpar];
	string par_cpos = *(*cpos)[par];
	string ch1_cpos = ch1 == par ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = *(*cpos)[ch2];

	string gpar_form = *(*forms)[gpar];
	string par_form = *(*forms)[par];
	string ch1_form = ch1 == par ? "STWRD" : *(*forms)[ch1];
	string ch2_form = *(*forms)[ch2];

	//Grand-TRIP
	//POS
	string GTrips_pos = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos;
	string tmp = "POS_GTRIPS=" + GTrips_pos;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//CPOS
	string GTrips_cpos = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "CPOS_GTRIPS=" + GTrips_cpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//FORM-POS
	string GTrips_fpos = gpar_pos + "_" + par_form + "_" + ch1_pos + "_" + ch2_pos;
	tmp = "FPOSP_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_form + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos;
	tmp = "FPOSG_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_pos + "_" + par_pos + "_" + ch1_form + "_" + ch2_pos;
	tmp = "FPOSC1_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_form;
	tmp = "FPOSC2_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_form + "_" + par_form + "_" + ch1_pos + "_" + ch2_pos;
	tmp = "FPOSGP_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_form + "_" + par_pos + "_" + ch1_form + "_" + ch2_pos;
	tmp = "FPOSGC1_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_form + "_" + par_pos + "_" + ch1_pos + "_" + ch2_form;
	tmp = "FPOSGC2_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_pos + "_" + par_form + "_" + ch1_form + "_" + ch2_pos;
	tmp = "FPOSPC1_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_pos + "_" + par_form + "_" + ch1_pos + "_" + ch2_form;
	tmp = "FPOSPC2_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fpos = gpar_pos + "_" + par_pos + "_" + ch1_form + "_" + ch2_form;
	tmp = "FPOSC12_GTRIPS=" + GTrips_fpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//FORM-CPOS
	string GTrips_fcpos = gpar_cpos + "_" + par_form + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "FCPOSP_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_form + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "FCPOSG_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_cpos + "_" + par_cpos + "_" + ch1_form + "_" + ch2_cpos;
	tmp = "FCPOSC1_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_form;
	tmp = "FCPOSC2_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_form + "_" + par_form + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "FCPOSGP_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_form + "_" + par_cpos + "_" + ch1_form + "_" + ch2_cpos;
	tmp = "FCPOSGC1_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_form + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_form;
	tmp = "FCPOSGC2_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_cpos + "_" + par_form + "_" + ch1_form + "_" + ch2_cpos;
	tmp = "FCPOSPC1_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_cpos + "_" + par_form + "_" + ch1_cpos + "_" + ch2_form;
	tmp = "FCPOSPC2_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	GTrips_fcpos = gpar_cpos + "_" + par_cpos + "_" + ch1_form + "_" + ch2_form;
	tmp = "FCPOSC12_GTRIPS=" + GTrips_fcpos;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//context features
	string gnt, pnt, c1nt, c2nt, gnc, pnc, c1nc, c2nc;
	string gpt, ppt, c1pt, c2pt, gpc, ppc, c1pc, c2pc;
	if(gpar < par){
		if(par < ch2){
			gnt  = (gpar < par - 1)               ? *(*pos)[gpar + 1] : "MPOS";
			pnt  = (par < ch1 - 1)                ? *(*pos)[par + 1]  : "MPOS";
			c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < instance->length() - 1) ? *(*pos)[ch2 + 1]  : "EPOS";

			gpt  = (gpar > 0)                     ? *(*pos)[gpar - 1] : "SPOS";
			ppt  = (par > gpar + 1)               ? *(*pos)[par - 1]  : "MPOS";
			c1pt = (ch1 > par + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < par - 1)               ? *(*cpos)[gpar + 1] : "MCPOS";
			pnc  = (par < ch1 - 1)                ? *(*cpos)[par + 1]  : "MCPOS";
			c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < instance->length() - 1) ? *(*cpos)[ch2 + 1]  : "ECPOS";

			gpc  = (gpar > 0)                     ? *(*cpos)[gpar - 1] : "SCPOS";
			ppc  = (par > gpar + 1)               ? *(*cpos)[par - 1]  : "MCPOS";
			c1pc = (ch1 > par + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
		else{
			gnt  = (gpar < ch2 - 1)               ? *(*pos)[gpar + 1] : "MPOS";
			pnt  = (par < instance->length() - 1) ? *(*pos)[par + 1]  : "EPOS";
			c1nt = (ch1 < par - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > 0)                     ? *(*pos)[gpar - 1] : "SPOS";
			ppt  = (par > ch1 + 1)                ? *(*pos)[par - 1]  : "MPOS";
			c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > gpar + 1)               ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < ch2 - 1)               ? *(*cpos)[gpar + 1] : "MCPOS";
			pnc  = (par < instance->length() - 1) ? *(*cpos)[par + 1]  : "ECPOS";
			c1nc = (ch1 < par - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > 0)                     ? *(*cpos)[gpar - 1] : "SCPOS";
			ppc  = (par > ch1 + 1)                ? *(*cpos)[par - 1]  : "MCPOS";
			c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > gpar + 1)               ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
	}
	else{
		if(par < ch2){
			gnt  = (gpar < instance->length() - 1)? *(*pos)[gpar + 1] : "EPOS";
			pnt  = (par < ch1 - 1)                ? *(*pos)[par + 1]  : "MPOS";
			c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < gpar - 1)               ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > ch2 + 1)               ? *(*pos)[gpar - 1] : "MPOS";
			ppt  = (par > 0)                      ? *(*pos)[par - 1]  : "SPOS";
			c1pt = (ch1 > par + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1]  : "MPOS";

			gnc  = (gpar < instance->length() - 1)? *(*cpos)[gpar + 1] : "ECPOS";
			pnc  = (par < ch1 - 1)                ? *(*cpos)[par + 1]  : "MCPOS";
			c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < gpar - 1)               ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > ch2 + 1)               ? *(*cpos)[gpar - 1] : "MCPOS";
			ppc  = (par > 0)                      ? *(*cpos)[par - 1]  : "SCPOS";
			c1pc = (ch1 > par + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1]  : "MCPOS";
		}
		else{
			gnt  = (gpar < instance->length() - 1)? *(*pos)[gpar + 1] : "EPOS";
			pnt  = (par < gpar - 1)               ? *(*pos)[par + 1]  : "MPOS";
			c1nt = (ch1 < par - 1)                ? *(*pos)[ch1 + 1]  : "MPOS";
			c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1]  : "MPOS";

			gpt  = (gpar > par + 1)               ? *(*pos)[gpar - 1] : "MPOS";
			ppt  = (par > ch1 + 1)                ? *(*pos)[par - 1]  : "MPOS";
			c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1]  : "MPOS";
			c2pt = (ch2 > 0)                      ? *(*pos)[ch2 - 1]  : "SPOS";

			gnc  = (gpar < instance->length() - 1)? *(*cpos)[gpar + 1] : "ECPOS";
			pnc  = (par < gpar - 1)               ? *(*cpos)[par + 1]  : "MCPOS";
			c1nc = (ch1 < par - 1)                ? *(*cpos)[ch1 + 1]  : "MCPOS";
			c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1]  : "MCPOS";

			gpc  = (gpar > par + 1)               ? *(*cpos)[gpar - 1] : "MCPOS";
			ppc  = (par > ch1 + 1)                ? *(*cpos)[par - 1]  : "MCPOS";
			c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1]  : "MCPOS";
			c2pc = (ch2 > 0)                      ? *(*cpos)[ch2 - 1]  : "SCPOS";
		}
	}
	/* 4-gram context features */
	//POS
	string context = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gnt + "_" + pnt + "_" + c2nt;
	tmp = "4GNPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gpt + "_" + ppt + "_" + c2pt;
	tmp = "4GPPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gnt + "_" + pnt;
	tmp = "4GNPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_pos + "_" + par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + gpt + "_" + ppt;
	tmp = "4GPPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	//CPOS
	context = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gnc + "_" + pnc + "_" + c2nc;
	tmp = "4GNCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gpc + "_" + ppc + "_" + c2pc;
	tmp = "4GPCPOS3_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gnc + "_" + pnc;
	tmp = "4GNCPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = gpar_cpos + "_" + par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + gpc + "_" + ppc;
	tmp = "4GPCPOS2_GNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe3OGSibling::writeExtendedFeatures(DependencyInstance *instance, ObjectWriter &out){
	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector prodFV = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
				}
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}
	}
	out.writeInt(-3);

	//coords
	vector<vector<vector<bool> > > coords = vector<vector<vector<bool> > >(instanceLength);
	for(int i = 0; i < instanceLength; i++){
		coords[i] = vector<vector<bool> >(instanceLength);
		for(int j = 0; j < instanceLength; j++){
			int nn;
			if(i == j){
				nn = 0;
			}
			else if(j < i){
				nn = i;
			}
			else{
				nn = instanceLength;
			}
			coords[i][j] = vector<bool>(nn);
			for(int k = 0; k < nn; k++){
				coords[i][j][k] = false;
			}
		}
	}

	bool coord;
	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w2; w3 < instanceLength; w3++){
				for(int w4 = w3 + 1; w4 < instanceLength; w4++){
					FeatureVector prodFV = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
			for(int w3 = w2; w3 > w1; w3--){
				for(int w4 = w3 - 1; w4 > w1; w4--){
					FeatureVector prodFV = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2; w3 < w1; w3++){
				for(int w4 = w3 + 1; w4 < w1; w4++){
					FeatureVector prodFV = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
			for(int w3 = w2; w3 >= 0; w3--){
				for(int w4 = w3 -1; w4 >= 0; w4--){
					FeatureVector prodFV = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						FeatureVector prodFV = FeatureVector();
						addGrandSibFeatures(instance, w1, w2, w3, wh == 0, &prodFV);
						int *keys = prodFV.keys();
						out.writeArray(keys, (int)(prodFV.size()));
						delete[](keys);
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						FeatureVector prodFV = FeatureVector();
						addGrandSibFeatures(instance, w1, w2, w3, wh == 0, &prodFV);
						int *keys = prodFV.keys();
						out.writeArray(keys, (int)(prodFV.size()));
						delete[](keys);
					}
				}
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector prodFV = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &prodFV);
				}
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 > w1; w3--){
				FeatureVector prodFV = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &prodFV);
				}
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2 + 1; w3 < w1; w3++){
				FeatureVector prodFV = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &prodFV);
				}
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector prodFV = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &prodFV);
				}
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}
	out.writeInt(-3);
}

DependencyInstance* DependencyPipe3OGSibling::readInstance(ObjectReader &in, int length, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<double> > > &probs_grands, std::vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &probs_gtrips, std::vector<vector<vector<vector<double> > > > &probs_gsibs, std::vector<vector<vector<double> > > &probs_coords, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	// Get production crap.
	for (int w1 = 0; w1 < length; w1++) {
		for (int w2 = w1 + 1; w2 < length; w2++) {
			for (int ph = 0; ph < 2; ph++) {
				int *keys = NULL;
				int size = in.readArray(keys);
				probs[w1][w2][ph] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	int last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	if (labeled) {
		for (int w1 = 0; w1 < length; w1++) {
			int len = (int)(types.size());
			for (int t = 0; t < len; t++) {
				for (int ph = 0; ph < 2; ph++) {
					for (int ch = 0; ch < 2; ch++) {
						int *keys = NULL;
						int size = in.readArray(keys);
						nt_probs[w1][t][ph][ch] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
		last = in.readInt();
		if (last != -3) {
			cout<<"Error reading file."<<endl;
			exit(0);
		}
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = 0; w2 <length; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_sibs[w1][w2][wh] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				if(w3 == w2){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w2; w3 < length; w3++){
				for(int w4 = w3 + 1; w4 < length; w4++){
					int *keys = NULL;
					int w = (w2 == w3 ? w4 - w1 - 1 : w4 - w3 - 1);
					int size = in.readArray(keys);
					probs_gtrips[w1][w2][w3 - w1 - 1][w] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
			for(int w3 = w2; w3 > w1; w3--){
				for(int w4 = w3 - 1; w4 > w1; w4--){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_gtrips[w1][w2][w3 - w1 - 1][w4 - w1 - 1] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2; w3 < w1; w3++){
				for(int w4 = w3 + 1; w4 < w1; w4++){
					int *keys = NULL;
					int w = (w2 == w3 ? w4 : w4 - w3 - 1);
					int size = in.readArray(keys);
					probs_gtrips[w1][w2][w3][w] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
			for(int w3 = w2; w3 >= 0; w3--){
				for(int w4 = w3 -1; w4 >= 0; w4--){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_gtrips[w1][w2][w3][w4] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						int *keys = NULL;
						int size = in.readArray(keys);
						probs_gsibs[w1][w2][w3][wh] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						int *keys = NULL;
						int size = in.readArray(keys);
						probs_gsibs[w1][w2][w3][wh] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_coords[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 > w1; w3--){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_coords[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2 + 1; w3 < w1; w3++){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_coords[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_coords[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	int *keys = NULL;
	int size = in.readArray(keys);
	FeatureVector* nfv = new FeatureVector();
	nfv->construct(keys, size);
	delete[](keys);
	last = in.readInt();
	if (last != -4) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	DependencyInstance* marshalledDI = new DependencyInstance();
	marshalledDI->readObject(in);
	marshalledDI->setFeatureVector(nfv);

	last = in.readInt();
	if (last != -1) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}
	return marshalledDI;
}

void DependencyPipe3OGSibling::fillFeatureVectors(DependencyInstance *instance, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<double> > > &probs_grands, std::vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &probs_gtrips, std::vector<vector<vector<vector<double> > > > &probs_gsibs, std::vector<vector<vector<double> > > &probs_coords, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	((DependencyPipe*)this)->fillFeatureVectors(instance, probs, nt_probs, params);

	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
		for(int w2 = w1; w2 >= 0 ; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector fv = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &fv);
					double prodProb = params->getScore(&fv);
					probs_sibs[w1][w2][wh] = prodProb;
				}
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}
	}

	//coords
	vector<vector<vector<bool> > > coords = vector<vector<vector<bool> > >(instanceLength);
	for(int i = 0; i < instanceLength; i++){
		coords[i] = vector<vector<bool> >(instanceLength);
		for(int j = 0; j < instanceLength; j++){
			int nn;
			if(i == j){
				nn = 0;
			}
			else if(j < i){
				nn = i;
			}
			else{
				nn = instanceLength;
			}
			coords[i][j] = vector<bool>(nn);
			for(int k = 0; k < nn; k++){
				coords[i][j][k] = false;
			}
		}
	}

	bool coord;
	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w2; w3 < instanceLength; w3++){
				for(int w4 = w3 + 1; w4 < instanceLength; w4++){
					int w = (w2 == w3 ? w4 - w1 - 1 : w4 - w3 - 1);
					FeatureVector fv = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_gtrips[w1][w2][w3 - w1 - 1][w] = prodProb;
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
			for(int w3 = w2; w3 > w1; w3--){
				for(int w4 = w3 - 1; w4 > w1; w4--){
					FeatureVector fv = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_gtrips[w1][w2][w3 - w1 - 1][w4 - w1 - 1] = prodProb;
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2; w3 < w1; w3++){
				for(int w4 = w3 + 1; w4 < w1; w4++){
					int w = (w2 == w3 ? w4 : w4 - w3 - 1);
					FeatureVector fv = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_gtrips[w1][w2][w3][w] = prodProb;
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
			for(int w3 = w2; w3 >= 0; w3--){
				for(int w4 = w3 -1; w4 >= 0; w4--){
					FeatureVector fv = FeatureVector();
					addGrandTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_gtrips[w1][w2][w3][w4] = prodProb;
					coord = isCoord(instance, w2, w3);
					if(coord){
						coords[w1][w2][w4] = true;
					}
				}
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						FeatureVector fv = FeatureVector();
						addGrandSibFeatures(instance, w1, w2, w3, wh == 0, &fv);
						double prodProb = params->getScore(&fv);
						probs_gsibs[w1][w2][w3][wh] = prodProb;
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(w2 != w3){
						FeatureVector fv = FeatureVector();
						addGrandSibFeatures(instance, w1, w2, w3, wh == 0, &fv);
						double prodProb = params->getScore(&fv);
						probs_gsibs[w1][w2][w3][wh] = prodProb;
					}
				}
			}
		}
	}
	
	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector fv = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &fv);
				}
				double prodProb = params->getScore(&fv);
				probs_coords[w1][w2][w3] = prodProb;
			}

			for(int w3 = w2 - 1; w3 > w1; w3--){
				FeatureVector fv = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &fv);
				}
				double prodProb = params->getScore(&fv);
				probs_coords[w1][w2][w3] = prodProb;
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2 + 1; w3 < w1; w3++){
				FeatureVector fv = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &fv);
				}
				double prodProb = params->getScore(&fv);
				probs_coords[w1][w2][w3] = prodProb;
			}

			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector fv = FeatureVector();
				if(coords[w1][w2][w3]){
					addCoordFeatures(instance, w1, w2, w3, &fv);
				}
				double prodProb = params->getScore(&fv);
				probs_coords[w1][w2][w3] = prodProb;
			}
		}
	}
}
